#!/usr/bin/env python3

import time
from hexbytes import HexBytes
import web3
from web3 import Web3
from multiprocessing import Pool
import traceback
from share import *

BLOCK_NUMBER_FILE = '.block_number'
DEBUG_PRINT_ALL = False
SCAN_START = 6513094

def get_tx_data(tx_hash):
  return w3.eth.get_transaction(tx_hash)

def scan_block(block_number: int, write_current_block=False):
  try:
    block = w3.eth.get_block(block_number)
    timestamp = block.timestamp
    txs = block.transactions

    # use process pool
    if USE_MULTI_PROCESS:
      pool = Pool(4)
      result = pool.map_async(get_tx_data, txs)
      tx_infos = result.get()
    else:
      tx_infos = []
      for tx in txs:
        tx_infos.append(get_tx_data(tx))

    if USE_DATABASE:
      clear_block_record(block_number)

    for tx_info in tx_infos:
      try:
        value = tx_info.value
        value_in_eth = value / 10**18
        from_addr = tx_info['from']
        to_addr = tx_info['to']
        from_balance = w3.eth.get_balance(from_addr) / 10**18
        if to_addr is None:
          to_balance = 0
        else:
          to_balance = w3.eth.get_balance(to_addr) / 10**18
        hash = tx_info.hash.hex()
        if DEBUG_PRINT_ALL or value_in_eth > ALERT_VALUE_IN_ETH and from_addr not in WHITE_LIST:
          alert_data = TxAlertData(block_number, timestamp, hash, value_in_eth, from_addr, to_addr, from_balance, to_balance)
          if USE_DATABASE:
            save_alert_data(alert_data)
          print(f'[{block_number}] {hash} | value: {value_in_eth}')
      except Exception as e:
        print(f'error on txn: {tx_info}')
        print(traceback.format_exc())

    with open(BLOCK_NUMBER_FILE, 'w') as f:
      f.write(str(block_number))
    
  except Exception as e:
    print(f'error on scan {block_number}')
    print(traceback.format_exc())

if __name__ == '__main__':
  try:
    with open(BLOCK_NUMBER_FILE) as f:
      bn_str = f.read()
      bn = int(bn_str)
  except Exception as e:
    print('block_number not set')
    print(e)
    exit()
  block_number = bn
  if block_number == 0:
    block_number = w3.eth.block_number - 1
  
  while True:
    highest = w3.eth.block_number - 1
    
    if highest > block_number:
      print(f'scan block: {block_number}')
      scan_block(block_number, True)
      block_number += 1
    else:
      print(f'wait for new block...(now {highest})')
      time.sleep(2)
    